//
//  MEEditShapeScene.m
//  MapEditor
//
//  Created by Eric on 3/5/12.
//  Copyright 2012 __MyCompanyName__. All rights reserved.
//

#import "MEEditShapeLayer.h"
#import "MEPrototype.h"
#import "BBUtil.h"
#import "MEDefine.h"
#import "MEUtil.h"


@implementation CCMenuItemFont(hide)
-(void)setOpacity:(GLubyte)opacity{
    for (CCNode* node in [self children]) {
        if ([node isKindOfClass:[CCLabelTTF class]]) {
            [(CCLabelTTF*)node setOpacity:opacity];
        }
    }
}
@end

@implementation MEEditShapeLayer
@synthesize prototype;
@synthesize line;
@synthesize rect;
@synthesize circle;
@synthesize polygon;
@synthesize moveSpt;
@synthesize shapes;
@synthesize done;
@synthesize cancel;
@synthesize spt;

-(void)dealloc{
    self.line = nil;
    self.rect = nil;
    self.circle = nil;
    self.polygon = nil;
    self.moveSpt = nil;
    self.prototype = nil;
    self.shapes = nil;
    self.done = nil;
    self.cancel = nil;
    self.spt = nil;
    [tmpShapePoints release];
    
    [super dealloc];
}
-(id)init{
    if (self=[super init]) {
        tmpShapePoints = [[NSMutableArray alloc]init];
        state = EDIT_SHAPE_STATE_LINE;
    }
    return self;
}


+(id)layer:(MEPrototype*)p done:(BBPackAction*)done cancel:(BBPackAction*)cancel{
    MEEditShapeLayer *layer = [[self class] layer];
    layer.prototype = p;
    layer.done = done;
    layer.cancel = cancel;
    return layer;
}

-(id)scene{
    CCScene *scene = [super scene];
    
    //[spt removeFromParentAndCleanup:YES];
    self.spt = [CCSprite spriteWithFile:prototype.filePath];
    spt.position = ccp(layerSize.width/2, layerSize.height/2);
    spt.scale = 1;
    [self addChild:spt z:-1];
    
    self.shapes = [NSMutableArray arrayWithArray:prototype.shapes];
    CGPoint p = prototype.shapeCenter;
    p.x *= -1;
    p.y *= -1;
    p.x += EDIT_SHAPE_CENTER.x;
    p.y += EDIT_SHAPE_CENTER.y;
    spt.position = p;
    
    [self resetBody];
    
    [self.line removeFromParentAndCleanup:YES];
    [self.rect removeFromParentAndCleanup:YES];
    [self.circle removeFromParentAndCleanup:YES];
    [self.polygon removeFromParentAndCleanup:YES];
    [self.moveSpt removeFromParentAndCleanup:YES];
    
    self.line = [CCMenuItemFont itemFromString:@"Line" target:self selector:@selector(stateChanged:)];
    self.line.fontSize = 18;
    self.line.tag = EDIT_SHAPE_STATE_LINE;
    self.line.opacity = EDIT_SHAPE_SELECTED;
    
    self.rect = [CCMenuItemFont itemFromString:@"Rect" target:self selector:@selector(stateChanged:)];
    self.rect.fontSize = 18;
    self.rect.tag = EDIT_SHAPE_STATE_RECT;
    self.rect.opacity = EDIT_SHAPE_UNSELECTED;
    
    self.circle = [CCMenuItemFont itemFromString:@"Circle" target:self selector:@selector(stateChanged:)];
    self.circle.fontSize = 18;
    self.circle.tag = EDIT_SHAPE_STATE_CIRCLE;
    self.circle.opacity = EDIT_SHAPE_UNSELECTED;
    
    self.polygon = [CCMenuItemFont itemFromString:@"Polygon" target:self selector:@selector(stateChanged:)];
    self.polygon.fontSize = 18;
    self.polygon.tag = EDIT_SHAPE_STATE_POLYGON;
    self.polygon.opacity = EDIT_SHAPE_UNSELECTED;
    
    self.moveSpt = [CCMenuItemFont itemFromString:@"Move" target:self selector:@selector(stateChanged:)];
    self.moveSpt.fontSize = 18;
    self.moveSpt.tag = EDIT_SHAPE_STATE_MOVE;
    self.moveSpt.opacity = EDIT_SHAPE_UNSELECTED;
    
    CCMenu* menu = [CCMenu menuWithItems:line, rect, circle, polygon, moveSpt, nil];
    [menu alignItemsVertically];
    menu.position = ccp(30,320);
    [scene addChild:menu];
    
    
    CCMenuItemFont *doneItem = [CCMenuItemFont itemFromString:@"Done" target:self selector:@selector(done:)];
    doneItem.fontSize = 18;
    doneItem.tag = 1;
    CCMenuItemFont *cancelItem = [CCMenuItemFont itemFromString:@"Cancel" target:self selector:@selector(done:)];
    cancelItem.fontSize = 18;
    cancelItem.tag = 0;
    CCMenu* menu2 = [CCMenu menuWithItems:doneItem, cancelItem, nil];
    [menu2 alignItemsHorizontally];
    menu2.position = ccp(45,30);
    [scene addChild:menu2];
    
	return scene;
}


-(void)stateChanged:(CCMenuItemFont*)item{
    state = item.tag;
    if (state==EDIT_SHAPE_STATE_LINE) {
        line.opacity = EDIT_SHAPE_SELECTED;
        rect.opacity = EDIT_SHAPE_UNSELECTED;
        circle.opacity = EDIT_SHAPE_UNSELECTED;
        polygon.opacity = EDIT_SHAPE_UNSELECTED;
        moveSpt.opacity = EDIT_SHAPE_UNSELECTED;
    }if (state==EDIT_SHAPE_STATE_RECT) {
        line.opacity = EDIT_SHAPE_UNSELECTED;
        rect.opacity = EDIT_SHAPE_SELECTED;
        circle.opacity = EDIT_SHAPE_UNSELECTED;
        polygon.opacity = EDIT_SHAPE_UNSELECTED;
        moveSpt.opacity = EDIT_SHAPE_UNSELECTED;
    }else if (state==EDIT_SHAPE_STATE_CIRCLE) {
        line.opacity = EDIT_SHAPE_UNSELECTED;
        rect.opacity = EDIT_SHAPE_UNSELECTED;
        circle.opacity = EDIT_SHAPE_SELECTED;
        polygon.opacity = EDIT_SHAPE_UNSELECTED;
        moveSpt.opacity = EDIT_SHAPE_UNSELECTED;
    }else if (state==EDIT_SHAPE_STATE_POLYGON){
        line.opacity = EDIT_SHAPE_UNSELECTED;
        rect.opacity = EDIT_SHAPE_UNSELECTED;
        circle.opacity = EDIT_SHAPE_UNSELECTED;
        polygon.opacity = EDIT_SHAPE_SELECTED;
        moveSpt.opacity = EDIT_SHAPE_UNSELECTED;
    }else if (state==EDIT_SHAPE_STATE_MOVE){
        line.opacity = EDIT_SHAPE_UNSELECTED;
        rect.opacity = EDIT_SHAPE_UNSELECTED;
        circle.opacity = EDIT_SHAPE_UNSELECTED;
        polygon.opacity = EDIT_SHAPE_UNSELECTED;
        moveSpt.opacity = EDIT_SHAPE_SELECTED;
    }
}

-(void)done:(CCMenuItemFont*)item{
    if (item.tag==1) {
        [done doAction];
    }else{
        [cancel doAction];
    }

}


-(void)resetBody{
    for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
    {
        b->SetUserData(NULL);
        world->DestroyBody(b);
    }
    if ([shapes count]>0) {        
        CGPoint pos = EDIT_SHAPE_CENTER;
        b2BodyDef bodyDef;
        bodyDef.type = b2_dynamicBody;        
        bodyDef.position.Set(pos.x/PTM_RATIO, pos.y/PTM_RATIO);
        b2Body* body = world->CreateBody(&bodyDef);
        
        for (NSDictionary*param in shapes) {
            NSInteger st = [param intValue:@"state" defaultVal:EDIT_SHAPE_STATE_CIRCLE];
            if (st==EDIT_SHAPE_STATE_LINE) {
                NSArray* points = [param valueForKey:@"points"];
                NSPoint p1 = [[points objectAtIndex:0] pointValue]; 
                CGFloat p1x = p1.x;
                CGFloat p1y = p1.y;
                
                NSPoint p2 = [[points objectAtIndex:1] pointValue];             
                CGFloat p2x = p2.x;
                CGFloat p2y = p2.y;
                
                
                b2PolygonShape shape;		
                shape.SetAsEdge(b2Vec2(p1x/PTM_RATIO, p1y/PTM_RATIO), b2Vec2(p2x/PTM_RATIO, p2y/PTM_RATIO));
                body->CreateFixture(&shape,0);
                
            }else if (st==EDIT_SHAPE_STATE_CIRCLE) {   
                NSArray* points = [param valueForKey:@"points"];
                NSPoint p1 = [[points objectAtIndex:0] pointValue]; 
                CGFloat p1x = p1.x;
                CGFloat p1y = p1.y;
                
                NSPoint p2 = [[points objectAtIndex:1] pointValue];             
                CGFloat p2x = p2.x;
                CGFloat p2y = p2.y;
                
                CGFloat r = sqrtf(powf(p1x - p2x, 2) + powf(p1y - p2y, 2));
                
                
                {
                    b2FixtureDef fixtureDef;
                    fixtureDef.density = 1;
                    fixtureDef.friction = 1;
                    fixtureDef.restitution = 1;
                    b2CircleShape dynamicBox;
                    CGFloat radius = r;
                    dynamicBox.m_radius = radius/PTM_RATIO;
                    dynamicBox.m_p = b2Vec2(p1x / PTM_RATIO, p1y / PTM_RATIO);
                    fixtureDef.shape = &dynamicBox;	
                    
                    body->CreateFixture(&fixtureDef);
                    
                }             
            }else if (st==EDIT_SHAPE_STATE_POLYGON || st==EDIT_SHAPE_STATE_RECT) {
                NSArray* points = [param objectForKey:@"points"];
               
                {
                    b2Vec2 vertices[32];
                    NSInteger i = 0;                
                    
                    for (NSValue* pv in points) {
                        CGPoint p = NSPointToCGPoint([pv pointValue]);
                        vertices[i++] = b2Vec2(p.x / PTM_RATIO, p.y / PTM_RATIO);
                    }
                    
                    
                    b2PolygonShape shape;
                    shape.Set(vertices, (int)[points count]);
                    
                    b2FixtureDef fixtureDef;
                    fixtureDef.density = 0;
                    fixtureDef.friction = 0;
                    fixtureDef.restitution = 0;
                    fixtureDef.shape = &shape;	
                    body->CreateFixture(&fixtureDef);        
                }
            }
        }
    }
}

-(BOOL)mouseDown:(NSEvent *)event{
    prePoint = [(CCDirectorMac*)[CCDirector sharedDirector] convertEventToGL:event];
    prePoint = [self convertToNodeSpace:prePoint];
 
    //prePoint.x /= self.scale;
    //prePoint.y /= self.scale;
    
    CGPoint pos = EDIT_SHAPE_CENTER;
    prePoint = ccpSub(prePoint, pos);
    
    if (state!=EDIT_SHAPE_STATE_MOVE) {
        if ([tmpShapePoints count]==0) {            
            [tmpShapePoints addObject:[NSValue valueWithPoint:NSPointFromCGPoint(prePoint)]];
        }else{
            prePoint = NSPointToCGPoint([[tmpShapePoints lastObject] pointValue]);
        }
    }

    curPoint = prePoint;
    return YES;	
}
-(BOOL)mouseDragged:(NSEvent *)event{
    curPoint = [(CCDirectorMac*)[CCDirector sharedDirector] convertEventToGL:event];  
    curPoint = [self convertToNodeSpace:curPoint];
    //curPoint.x /= self.scale;
    //curPoint.y /= self.scale;
    CGPoint pos = EDIT_SHAPE_CENTER;
    curPoint = ccpSub(curPoint, pos);
    
    if (state==EDIT_SHAPE_STATE_MOVE) {
        CGPoint moveBy = ccpSub(curPoint, prePoint); 
        prePoint = curPoint;
        spt.position = ccpAdd(spt.position, moveBy);
        return NO;
    }
    
    return YES;
}
-(BOOL)mouseUp:(NSEvent *)event{
    @synchronized(self){
        CGFloat disHold = 10;
        CGFloat dis = sqrtf(powf(prePoint.x - curPoint.x, 2) + powf(prePoint.y - curPoint.y, 2));
        if (state==EDIT_SHAPE_STATE_LINE) {            
            if (dis<disHold) {
                [tmpShapePoints removeAllObjects];
                prePoint = CGPointZero;
                curPoint = CGPointZero;
                return NO;
            }
            NSArray* points = [NSArray arrayWithObjects:
                               [NSValue valueWithPoint:NSPointFromCGPoint(prePoint)], 
                               [NSValue valueWithPoint:NSPointFromCGPoint(curPoint)], 
                               nil];
            NSDictionary* param = [NSDictionary dictionaryWithObjectsAndKeys:
                                   [NSNumber numberWithInteger:state], @"state",
                                   points, @"points",
                                   nil];
            [shapes addObject:param];
            
            [tmpShapePoints removeAllObjects];
            prePoint = CGPointZero;
            curPoint = CGPointZero;
            
        }else if (state==EDIT_SHAPE_STATE_RECT) {
            if (dis<disHold) {
                [tmpShapePoints removeAllObjects];
                prePoint = CGPointZero;
                curPoint = CGPointZero;
                return NO;
            }
            CGPoint p1 = prePoint;
            CGPoint p3 = curPoint;
            CGPoint p2 = ccp(p1.x, p3.y);
            CGPoint p4 = ccp(p3.x, p1.y);
            
            NSArray* points = [NSArray arrayWithObjects:
                               [NSValue valueWithPoint:NSPointFromCGPoint(p1)], 
                               [NSValue valueWithPoint:NSPointFromCGPoint(p2)], 
                               [NSValue valueWithPoint:NSPointFromCGPoint(p3)], 
                               [NSValue valueWithPoint:NSPointFromCGPoint(p4)], 
                               nil];
            CCArray *newAray = [CCArray arrayWithNSArray:points];
            BOOL clockWise = [MEUtil isClockWise:points];
            if (!clockWise) {
                [newAray reverseObjects];
            }
            NSDictionary* param = [NSDictionary dictionaryWithObjectsAndKeys:
                                   [NSNumber numberWithInteger:state], @"state",
                                   newAray, @"points",
                                   nil];
            [shapes addObject:param];
            
            [tmpShapePoints removeAllObjects];
            prePoint = CGPointZero;
            curPoint = CGPointZero;
        }else if (state==EDIT_SHAPE_STATE_CIRCLE) {
            if (dis<disHold) {
                [tmpShapePoints removeAllObjects];
                prePoint = CGPointZero;
                curPoint = CGPointZero;
                return NO;
            }
            NSArray* points = [NSArray arrayWithObjects:
                               [NSValue valueWithPoint:NSPointFromCGPoint(prePoint)], 
                               [NSValue valueWithPoint:NSPointFromCGPoint(curPoint)], 
                               nil];
            NSDictionary* param = [NSDictionary dictionaryWithObjectsAndKeys:
                                   [NSNumber numberWithInteger:state], @"state",
                                   points, @"points",
                                   nil];
            [shapes addObject:param];
            
            [tmpShapePoints removeAllObjects];
            prePoint = CGPointZero;
            curPoint = CGPointZero;
        }else if(state == EDIT_SHAPE_STATE_POLYGON){
            if ([tmpShapePoints count]>2) {
                CGPoint firstP = NSPointToCGPoint([ [tmpShapePoints objectAtIndex:0] pointValue]);
                
                CGFloat d = sqrtf(powf(firstP.x - curPoint.x, 2) + powf(firstP.y - curPoint.y, 2));
                if (d<10) {      
                    //Reorder
                    CCArray *newAray = [CCArray arrayWithNSArray:tmpShapePoints];
                    BOOL clockWise = [MEUtil isClockWise:tmpShapePoints];
                    if (!clockWise) {
                        [newAray reverseObjects];
                    }
                    
                    NSDictionary* param = [NSDictionary dictionaryWithObjectsAndKeys:
                                           [NSNumber numberWithInteger:state], @"state",
                                           newAray, @"points",
                                           nil];
                    [shapes addObject:param];
                    
                    [tmpShapePoints removeAllObjects];
                    prePoint = CGPointZero;
                    curPoint = CGPointZero;
                }else{
                    d = sqrtf(powf(prePoint.x - curPoint.x, 2) + powf(prePoint.y - curPoint.y, 2));
                    if (d>10) {
                        [tmpShapePoints addObject:[NSValue valueWithPoint:NSPointFromCGPoint(curPoint)]];
                    }  
                    prePoint = CGPointZero;
                    curPoint = CGPointZero;
                }
                
            }else{
                [tmpShapePoints addObject:[NSValue valueWithPoint:NSPointFromCGPoint(curPoint)]];
            }
        }

        [self resetBody];
    }
    return YES;
}


-(void)rightClick:(NSEvent *)event{
    CGPoint p = [(CCDirectorMac*)[CCDirector sharedDirector] convertEventToGL:event];
    p = [self convertToNodeSpace:p];
    //p.x /= self.scale;
    //p.y /= self.scale;
    p = ccpSub(p, EDIT_SHAPE_CENTER);
    for (NSDictionary*param in shapes) {
        BOOL hit = NO;
        NSInteger st = [param intValue:@"state" defaultVal:EDIT_SHAPE_STATE_CIRCLE];
        
        if (st==EDIT_SHAPE_STATE_LINE) {
            NSArray* points = [param valueForKey:@"points"];
            CGPoint p1 = NSPointToCGPoint([[points objectAtIndex:0] pointValue]);             
            CGPoint p2 = NSPointToCGPoint([[points objectAtIndex:1] pointValue]);             
            CGFloat dis = [MEUtil distance:p1 p2:p2 p3:p];
            hit = dis < 10; 
        }else if (st==EDIT_SHAPE_STATE_CIRCLE) {   
            NSArray* points = [param valueForKey:@"points"];
            NSPoint p1 = [[points objectAtIndex:0] pointValue]; 
            CGFloat p1x = p1.x;
            CGFloat p1y = p1.y;
            
            NSPoint p2 = [[points objectAtIndex:1] pointValue];             
            CGFloat p2x = p2.x;
            CGFloat p2y = p2.y;
            
            CGFloat r = sqrtf(powf(p1x - p2x, 2) + powf(p1y - p2y, 2));
            CGFloat d = sqrtf(powf(p1x - p.x, 2) + powf(p1y - p.y, 2)); 
            hit = d<r;
        }else if (st==EDIT_SHAPE_STATE_POLYGON || st==EDIT_SHAPE_STATE_RECT) {  
            NSArray* points = [param valueForKey:@"points"];
            hit = [MEUtil isInPolygon:points point:p];
        }
        if (hit) {
            NSMenu* rightClick =  [[NSMenu alloc] initWithTitle:@"RightClick"];
            
            //Add NSMenuItem(s) to the rightClick NSMenu
            NSMenuItem* remove = [[[NSMenuItem  alloc] init] autorelease];
            [remove setTitle:@"Remove?"];
            [remove setRepresentedObject:param];
            [remove setAction:@selector(removeParam:)];
            [remove setTarget:self];
            [rightClick addItem:remove];
            
            [NSMenu popUpContextMenu:rightClick withEvent:event forView:[CCDirector sharedDirector].openGLView];
            break;
        }
        
    }
}
-(void)removeParam:(NSMenuItem*)obj{
    @synchronized(self){
        [shapes removeObject:obj.representedObject];
        [self resetBody];
    }
}
-(CGPoint)bodyCenter{
    CGPoint p = spt.position;
    p.x -= EDIT_SHAPE_CENTER.x;
    p.y -= EDIT_SHAPE_CENTER.y;
    p.x *= -1;
    p.y *= -1;
    return p;
}


-(void)draw{
    [super draw];
    
    glLineWidth(1.0f);
    glEnable(GL_POINT_SMOOTH);
    glEnable(GL_LINE_SMOOTH);
    
    glColor4f(1.f, 0.f, 0.f, 1); 
    
    CGPoint pos = EDIT_SHAPE_CENTER;
    //pos = ccpAdd(pos, ccpSub(self.position, relatePoint));
    
    CGPoint p0 = ccpAdd(pos, prePoint);
    CGPoint p1 = ccpAdd(pos, curPoint);
    
    /*
    p0.x *= self.scale;
    p0.y *= self.scale;
    p1.x *= self.scale;
    p1.y *= self.scale;
    
    p0 = [self convertToNodeSpace:p0];
    p1 = [self convertToNodeSpace:p1];
    */
     
    ccDrawLine(p0, p1);
    
    if (prePoint.x!=curPoint.x && prePoint.y!=curPoint.y) {
        if (state==EDIT_SHAPE_STATE_RECT) {
            CGPoint pr1 = p0;
            CGPoint pr3 = p1;
            CGPoint pr2 = ccp(pr3.x, pr1.y);
            CGPoint pr4 = ccp(pr1.x, pr3.y);
            CGPoint points[4] = {pr1, pr2, pr3, pr4};
            ccDrawPoly(points, 4, YES);
        }else if (state==EDIT_SHAPE_STATE_CIRCLE) {
            CGPoint center = p0;
            CGFloat r = sqrtf(powf(p0.x - p1.x, 2) + powf(p0.y - p1.y, 2));
            ccDrawCircle(center, r, 60, 360, NO);
        }
    }
    if ([tmpShapePoints count]>1) {
        for (NSInteger i=0; i<[tmpShapePoints count]-1; i++) {
            CGPoint tp0 = NSPointToCGPoint([[tmpShapePoints objectAtIndex:i] pointValue]);
            CGPoint tp1 = NSPointToCGPoint([[tmpShapePoints objectAtIndex:i+1] pointValue]);
            
            tp0 = ccpAdd(pos, tp0);
            tp1 = ccpAdd(pos, tp1);
            ccDrawLine(tp0, tp1);
        }
    }  
     
    
    
    ccDrawCircle(ccp(480, 320), 5, 60, 360, NO);
    
    glDisable(GL_LINE_SMOOTH);
    glDisable(GL_POINT_SMOOTH);
}

-(NSMutableArray*)shapes{
    NSMutableArray* newAry = [NSMutableArray arrayWithCapacity:[shapes count]];
    for (NSDictionary*param in shapes) {
        NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithDictionary:param];
        
        NSArray* points = [param objectForKey:@"points"];           
        NSMutableArray* newPoints = [NSMutableArray arrayWithCapacity:[points count]];
        for (NSValue* pv in points) {
            CGPoint p = NSPointToCGPoint([pv pointValue]);
            p.x /= spt.scale;
            p.y /= spt.scale;
            NSValue* newPv = [NSValue valueWithPoint:p];
            [newPoints addObject:newPv];
        }
        [newDict setObject:newPoints forKey:@"points"];
        [newAry addObject:newDict];
    }
    return newAry;
}


@end
